{{- define "ingress-controller" }}
{{- $context := index . 0 }}
{{- $crd := index . 1 }}
{{- $name := index . 2 }}
{{- $failover := index . 3 }}
{{- $crdChecksum := toJson $crd | sha256sum }}
{{- $loadBalancer := (or (eq $crd.spec.inlet "LoadBalancer") (eq $crd.spec.inlet "LoadBalancerWithProxyProtocol")) }}
{{- $controllerVersion := $crd.spec.controllerVersion | default $context.Values.ingressNginx.defaultControllerVersion }}
{{- $kubernetesVersion := $context.Values.global.discovery.kubernetesVersion }}

{{- $resourcesRequests := $crd.spec.resourcesRequests | default dict }}
{{- $geoIP2 := $crd.spec.geoIP2 | default dict }}
{{- $hostPort := $crd.spec.hostPort | default dict }}
{{- $hostPortWithProxyProtocol := $crd.spec.hostPortWithProxyProtocol | default dict }}
{{- $gracePeriod := 0 }}
{{- $defaultGracePeriod := 60 }}
{{- if $loadBalancer }}
  {{- $defaultGracePeriod = 120 }}
{{- else if eq $crd.spec.inlet "HostWithFailover" }}
  {{- $defaultGracePeriod = 0 }}
{{- end }}
{{- $gracePeriod = (kindIs "invalid" $crd.spec.waitLoadBalancerOnTerminating) | ternary $defaultGracePeriod $crd.spec.waitLoadBalancerOnTerminating }}
{{- $defaultSSLCertificate := $crd.spec.defaultSSLCertificate | default dict }}
{{- $defaultSSLCertificateSecretRef := $defaultSSLCertificate.secretRef | default dict }}

{{- if ( $context.Values.global.enabledModules | has "vertical-pod-autoscaler-crd") }}
---
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: controller-{{ $name }}
  namespace: d8-ingress-nginx
  {{ include "helm_lib_module_labels" (list $context (dict "app" "controller" "name" $name )) | nindent 2 }}
spec:
  targetRef:
    apiVersion: "apps.kruise.io/v1alpha1"
    kind: DaemonSet
    name: controller-{{ $name }}
    {{- if eq ($resourcesRequests.mode | default "") "VPA" }}
      {{- $resourcesRequestsVPA := $resourcesRequests.vpa | default dict }}
      {{- $resourcesRequestsVPA_CPU := $resourcesRequestsVPA.cpu | default dict }}
      {{- $resourcesRequestsVPA_Memory := $resourcesRequestsVPA.memory | default dict }}
  updatePolicy:
    updateMode: {{ $resourcesRequestsVPA.mode | default "Initial" | quote }}
  resourcePolicy:
    containerPolicies:
    - containerName: controller
      minAllowed:
        cpu: {{ $resourcesRequestsVPA_CPU.min | default "10m" | quote }}
        memory: {{ $resourcesRequestsVPA_Memory.min | default "50Mi" | quote }}
      maxAllowed:
        cpu: {{ $resourcesRequestsVPA_CPU.max | default "50m" | quote }}
        memory: {{ $resourcesRequestsVPA_Memory.max | default "200Mi" | quote }}
    {{- else }}
  updatePolicy:
    updateMode: "Off"
    {{- end }}
{{- end }}
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: controller-{{ $name }}
  namespace: d8-ingress-nginx
  {{ include "helm_lib_module_labels" (list $context (dict "app" "controller" "name" $name "init" (now | date "20060102150405"))) | nindent 2 }}
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: controller
      name: {{ $name }}
---
apiVersion: apps.kruise.io/v1alpha1
kind: DaemonSet
metadata:
  name: controller-{{ $name }}
  namespace: d8-ingress-nginx
  {{- include "helm_lib_module_labels" (list $context (dict "app" "controller" "name" $name)) | nindent 2 }}
  {{- if eq $crd.spec.inlet "HostWithFailover" }}
    {{- if $failover }}
    ingress-nginx-failover: ""
    {{- end }}
  {{- end }}
  annotations:
    ingress-nginx-controller.deckhouse.io/controller-version: {{ $controllerVersion | quote }}
    ingress-nginx-controller.deckhouse.io/inlet: {{ $crd.spec.inlet | quote }}
    ingress-nginx-controller.deckhouse.io/checksum: {{ $crdChecksum }}
spec:
  revisionHistoryLimit: 3
{{/*  OpenKruise controller can handle minReadySeconds even for HostWithFailover inlet (while hook can't) */}}
{{/*  We want to add some delay to avoid immediately pod rollout and give some time for traffic to be handled */}}
  minReadySeconds: 60
  updateStrategy:
    type: RollingUpdate
    {{- if $loadBalancer }}
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
    {{- else }}
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 0
    {{- end }}
  {{- if and (eq $crd.spec.inlet "HostWithFailover") (not $failover) }}
{{/*  Extra functionality by kruise-controller  https://openkruise.io/docs/user-manuals/advanceddaemonset#lifecycle-hook*/}}
  lifecycle:
    preDelete:
      labelsHandler:
        ingress.deckhouse.io/block-deleting: "true"
  {{- end }}
  selector:
    matchLabels:
      app: controller
      name: {{ $name }}
  template:
    metadata:
      labels:
      {{- if and (eq $crd.spec.inlet "HostWithFailover") (not $failover) }}
        ingress.deckhouse.io/block-deleting: "true"
      {{- end }}
      {{- if $crd.spec.enableIstioSidecar }}
        sidecar.istio.io/inject: "true"
      {{- end }}
        app: controller
        name: {{ $name }}
      {{- if $crd.spec.enableIstioSidecar }}
      annotations:
        traffic.sidecar.istio.io/includeInboundPorts: ""
        traffic.sidecar.istio.io/includeOutboundIPRanges: {{ $context.Values.global.discovery.serviceSubnet | quote }}
        inject.istio.io/templates: "sidecar,d8-hold-istio-proxy-termination-until-application-stops"
      {{- end }}
    spec:
  {{- if $crd.spec.nodeSelector }}
      nodeSelector:
        {{- $crd.spec.nodeSelector | toYaml | nindent 8 }}
  {{- else }}
      {{- include "helm_lib_node_selector" (tuple $context "frontend") | nindent 6 }}
  {{- end }}
  {{- if $crd.spec.tolerations }}
      tolerations:
      {{- $crd.spec.tolerations | toYaml | nindent 6 }}
  {{- else }}
{{- include "helm_lib_tolerations" (tuple $context "frontend") | nindent 6 }}
  {{- end }}
{{- include "helm_lib_priority_class" (tuple $context "system-cluster-critical") | nindent 6 }}
      serviceAccountName: ingress-nginx
      terminationGracePeriodSeconds: 420
  {{- if and (eq $crd.spec.inlet "HostWithFailover") (not $failover) }}
      dnsPolicy: ClusterFirstWithHostNet
      hostNetwork: true
  {{- else }}
      dnsPolicy: ClusterFirst
      hostNetwork: false
  {{- end }}
      imagePullSecrets:
      - name: deckhouse-registry
      containers:
      - image: {{ include "helm_lib_module_image" (list $context (printf "controller%s" ($controllerVersion | replace "." ""))) }}
        name: controller
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_IP
          value: "127.0.0.1"
        {{- if $geoIP2.maxmindLicenseKey }}
        - name: LUA_USE_GEOIP2
          value: "true"
        {{- end }}
        livenessProbe:
          httpGet:
            path: /controller/healthz
            port: 10354
            scheme: HTTPS
          initialDelaySeconds: 30
          timeoutSeconds: 5
          periodSeconds: 10
          failureThreshold: 10
        readinessProbe:
          httpGet:
            path: /controller/healthz
            port: 10354
            scheme: HTTPS
          initialDelaySeconds: 10
          periodSeconds: 2
          timeoutSeconds: 5
        args:
        - /nginx-ingress-controller
        - --configmap=$(POD_NAMESPACE)/{{ $name }}-config
        - --v=2
        - --ingress-class={{ $crd.spec.ingressClass }}
        - --healthz-port=10254
        - --http-port=80
        - --https-port=443
        - --update-status=true
        {{- if $loadBalancer }}
        - --publish-service=d8-ingress-nginx/{{ $crd.name }}-load-balancer
        {{- end }}
        # sleep before shutting down the nginx, required by cloud LoadBalancers to terminate gracefully.
        - --shutdown-grace-period={{ $gracePeriod }}
        {{- if or (ne $crd.spec.inlet "HostWithFailover") (and (eq $crd.spec.inlet "HostWithFailover") ($failover)) }}
        # we don't disable it if validation is disabled because it will lead to deployment rollout
        - --validating-webhook=:8443
        - --validating-webhook-certificate=/etc/nginx/webhook-ssl/tls.crt
        - --validating-webhook-key=/etc/nginx/webhook-ssl/tls.key
        {{- end }}
        {{- if $defaultSSLCertificateSecretRef.name }}
        - --default-ssl-certificate={{ printf "%s/%s" $defaultSSLCertificateSecretRef.namespace $defaultSSLCertificateSecretRef.name }}
        {{- end }}
        - --controller-class={{ printf "ingress-nginx.deckhouse.io/%s" $crd.spec.ingressClass }}
        {{- if eq "nginx" $crd.spec.ingressClass }}
        - --watch-ingress-without-class=true
        {{- end }}
        {{- if and $crd.spec.annotationValidationEnabled (eq $controllerVersion "1.9") }}
        - --enable-annotation-validation=true
        {{- end }}
  {{- if $crd.spec.customErrors }}
        - --default-backend-service={{ $crd.spec.customErrors.namespace }}/{{ $crd.spec.customErrors.serviceName }}
  {{- end }}
    {{- if $geoIP2.maxmindLicenseKey }}
        - --maxmind-license-key={{ $geoIP2.maxmindLicenseKey }}
      {{- if $geoIP2.maxmindEditionIDs }}
        - --maxmind-edition-ids={{ $geoIP2.maxmindEditionIDs | join "," }}
      {{- end }}
    {{- end }}
        - --healthz-host=127.0.0.1
        - --election-id={{ printf "ingress-controller-leader-%s" $crd.spec.ingressClass }}
        lifecycle:
          preStop:
            exec:
              command:
                - /wait-shutdown
        resources:
          requests:
            {{- include "helm_lib_module_ephemeral_storage_logs_with_extra" 100 | nindent 12 }}
  {{- if and $loadBalancer (not $resourcesRequests) }}
            cpu: "350m"
            memory: "500Mi"
  {{- else if eq ($resourcesRequests.mode | default "") "Static" }}
    {{- $resourcesRequestsStatic := $resourcesRequests.static | default dict }}
            cpu: {{ $resourcesRequestsStatic.cpu | default "350m" | quote }}
            memory: {{ $resourcesRequestsStatic.memory | default "500Mi" | quote }}
  {{- end }}
        ports:
        - containerPort: 80
  {{- if eq $crd.spec.inlet "HostPort"}}
    {{- if $hostPort.httpPort }}
          hostPort: {{ $hostPort.httpPort }}
    {{- end }}
  {{- end }}
  {{- if eq $crd.spec.inlet "HostPortWithProxyProtocol"}}
    {{- if $hostPortWithProxyProtocol.httpPort }}
          hostPort: {{ $hostPortWithProxyProtocol.httpPort }}
    {{- end }}
  {{- end }}
        - containerPort: 443
  {{- if eq $crd.spec.inlet "HostPort"}}
    {{- if $hostPort.httpsPort }}
          hostPort: {{ $hostPort.httpsPort }}
    {{- end }}
  {{- end }}
  {{- if eq $crd.spec.inlet "HostPortWithProxyProtocol"}}
    {{- if $hostPortWithProxyProtocol.httpsPort }}
          hostPort: {{ $hostPortWithProxyProtocol.httpsPort }}
    {{- end }}
  {{- end }}
  {{- if or (ne $crd.spec.inlet "HostWithFailover") (and (eq $crd.spec.inlet "HostWithFailover") ($failover)) }}
        - containerPort: 8443
          protocol: TCP
          name: webhook
  {{- end }}
        volumeMounts:
  {{- if eq $controllerVersion "1.9" }}
        - mountPath: /chroot/var/lib/nginx/body
          name: client-body-temp-path
        - mountPath: /chroot/var/lib/nginx/fastcgi
          name: fastcgi-temp-path
        - mountPath: /chroot/var/lib/nginx/proxy
          name: proxy-temp-path
        - mountPath: /chroot/var/lib/nginx/scgi
          name: scgi-temp-path
        - mountPath: /chroot/var/lib/nginx/uwsgi
          name: uwsgi-temp-path
        - mountPath: /chroot/etc/nginx/ssl/
          name: secret-nginx-auth-tls
        - mountPath: /chroot/tmp/nginx/
          name: tmp-nginx
        - mountPath: /chroot/etc/nginx/webhook-ssl/
          name: webhook-cert
          readOnly: true
  {{- else }}
        - mountPath: /var/lib/nginx/body
          name: client-body-temp-path
        - mountPath: /var/lib/nginx/fastcgi
          name: fastcgi-temp-path
        - mountPath: /var/lib/nginx/proxy
          name: proxy-temp-path
        - mountPath: /var/lib/nginx/scgi
          name: scgi-temp-path
        - mountPath: /var/lib/nginx/uwsgi
          name: uwsgi-temp-path
        - mountPath: /etc/nginx/ssl/
          name: secret-nginx-auth-tls
        - mountPath: /tmp/nginx/
          name: tmp-nginx
        - mountPath: /etc/nginx/webhook-ssl/
          name: webhook-cert
          readOnly: true
  {{- end }}
      - image: {{ include "helm_lib_module_image" (list $context "protobufExporter") }}
        name: protobuf-exporter
        resources:
          requests:
            memory: 20Mi
            cpu: 10m
            {{- include "helm_lib_module_ephemeral_storage_only_logs" . | nindent 12 }}
        volumeMounts:
          - mountPath: /var/files
            name: telemetry-config-file
      - name: kube-rbac-proxy
        image: {{ include "helm_lib_module_image" (list $context "kubeRbacProxy") }}
        args:
        - "--secure-listen-address=$(KUBE_RBAC_PROXY_LISTEN_ADDRESS):10354"
        - "--v=2"
        - "--logtostderr=true"
        - "--stale-cache-interval=1h30m"
        env:
        - name: KUBE_RBAC_PROXY_LISTEN_ADDRESS
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: KUBE_RBAC_PROXY_CONFIG
          value: |
            excludePaths:
            - /controller/healthz
            upstreams:
            - upstream: http://127.0.0.1:10254/
              path: /controller/
              authorization:
                resourceAttributes:
                  namespace: d8-ingress-nginx
                  apiGroup: apps
                  apiVersion: v1
                  resource: daemonsets
                  subresource: prometheus-controller-metrics
                  name: ingress-nginx
            - upstream: http://127.0.0.1:9091/metrics
              path: /protobuf/metrics
              authorization:
                resourceAttributes:
                  namespace: d8-ingress-nginx
                  apiGroup: apps
                  apiVersion: v1
                  resource: daemonsets
                  subresource: prometheus-protobuf-metrics
                  name: ingress-nginx
        lifecycle:
          preStop:
            exec:
              command:
              - /controller-probe
              - -server
              - 127.0.0.1:10254
        ports:
        - containerPort: 10354
          name: https-metrics
        resources:
          requests:
            memory: 20Mi
            cpu: 10m
            {{- include "helm_lib_module_ephemeral_storage_only_logs" . | nindent 12 }}
      volumes:
      - name: tmp-nginx
        emptyDir: {}
      - name: client-body-temp-path
        emptyDir: {}
      - name: fastcgi-temp-path
        emptyDir: {}
      - name: proxy-temp-path
        emptyDir: {}
      - name: scgi-temp-path
        emptyDir: {}
      - name: uwsgi-temp-path
        emptyDir: {}
      - name: secret-nginx-auth-tls
        secret:
          secretName: ingress-nginx-{{ $crd.name }}-auth-tls
      - name: webhook-cert
        secret:
          secretName: ingress-admission-certificate
      - name: telemetry-config-file
        configMap:
          name: d8-ingress-telemetry-config
{{- end }}

{{- $context := . }}
{{- range $crd := $context.Values.ingressNginx.internal.ingressControllers }}
  {{ include "ingress-controller" (list $context $crd $crd.name false) }}

  {{- if eq $crd.spec.inlet "HostWithFailover" }}
    {{ include "ingress-controller" (list $context $crd (printf "%s-failover" $crd.name) true) }}
  {{- end }}
{{- end }}
